package com.wyl.template.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.wyl.template.domain.common.ResponseResult;
import com.wyl.template.domain.dto.SysPermissionDTO;
import com.wyl.template.domain.model.SysPermissionDO;
import com.wyl.template.domain.model.SysRoleDO;
import com.wyl.template.domain.model.SysUserDO;
import com.wyl.template.domain.vo.PermissionVO;
import com.wyl.template.enums.PermissionType;
import com.wyl.template.exception.BusinessException;
import com.wyl.template.exception.ErrorCodeEnum;
import com.wyl.template.mapper.SysPermissionMapper;
import com.wyl.template.service.SysPermissionService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.wyl.template.service.SysRolePermissionService;
import com.wyl.template.service.SysRoleService;
import com.wyl.template.util.ObjConverter;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;

/**
 * <p>
 * 权限表 服务实现类
 * </p>
 *
 * @author wyl
 * @since 2021-06-11
 */
@Service
public class SysPermissionServiceImpl extends ServiceImpl<SysPermissionMapper, SysPermissionDO> implements SysPermissionService {

    @Autowired
    private SysPermissionMapper permissionMapper;

    @Autowired
    private SysRolePermissionService rolePermissionService;

    @Autowired
    private SysRoleService roleService;

    private static final String ROOT_NAME = "root";


    @Override
    public List<SysPermissionDO> listUserPermissions(Long userId) {
        // 超级管理员可以获得所有列表
        List<SysRoleDO> sysRoleDOS = roleService.listUserRoles(userId);
        AtomicBoolean isRoot = new AtomicBoolean(false);
        sysRoleDOS.forEach(role -> {
            if (ROOT_NAME.equals(role.getRoleName())) {
                isRoot.set(true);
                return;
            }
        });
        List<SysPermissionDO> sysPermissionDOS;
        // 超级管理员获得所有的
        if (isRoot.get()) {
//            sysPermissionDOS = permissionMapper.listUserPermissions(null);

            QueryWrapper queryWrapper = new QueryWrapper();
            queryWrapper.orderByAsc("parent_id,priority");
            sysPermissionDOS = permissionMapper.selectList(queryWrapper);

        }else{
            sysPermissionDOS = permissionMapper.listUserPermissions(userId);
        }
        return sysPermissionDOS;
    }

    @Override
    public List<SysPermissionDTO> listPermissions() {
        List<SysPermissionDO> list = list();
        return transferDTO(list);
    }

    @Override
    public List<SysPermissionDTO> listMenusByParentId(Long parendId) {
        SysPermissionDO permissionDO = new SysPermissionDO();
        permissionDO.setParentId(parendId);
        QueryWrapper<SysPermissionDO> queryWrapper = new QueryWrapper<>(permissionDO);
        queryWrapper.orderByAsc("priority");
        List<SysPermissionDO> list = list(queryWrapper);
        return transferDTO(list);
    }

    /**
     * 查询用户具有的权限的目录
     *
     * @param userId
     * @return
     */
    @Override
    public List<PermissionVO> listMenuListByUser(Long userId) {
        List<SysPermissionDO> permissionList = listUserPermissions(userId);

        /*筛选出根目录*/
        List<PermissionVO> rootList = filterPermissionRoot(permissionList);

        filterPermissionVO(rootList, permissionList);

        return rootList;
    }

    /**
     * 筛选出根目录
     *
     * @param list
     * @return
     */
    List<PermissionVO> filterPermissionRoot(List<SysPermissionDO> list) {
        List<SysPermissionDO> rootList = list.stream().filter(item -> {
            return PermissionType.ROOT.getCode().equals(item.getType());
        }).collect(Collectors.toList());
        return rootList.stream().map(item -> {
            PermissionVO permissionVO = ObjConverter.convert(item, PermissionVO.class);
            permissionVO.setChildren(new ArrayList<>());
            return permissionVO;
        }).collect(Collectors.toList());
    }

    /**
     * 递归筛选出子目录
     *
     * @param parentList
     * @param list
     */
    void filterPermissionVO(List<PermissionVO> parentList, List<SysPermissionDO> list) {
        List<PermissionVO> childList = new ArrayList<>();

        /*先筛选出当前目录列表的所有子目录*/
        parentList.forEach(parent -> {
            list.forEach(child -> {
                if (parent.getId().equals(child.getParentId())) {
                    PermissionVO permissionVO = ObjConverter.convert(child, PermissionVO.class);
                    permissionVO.setChildren(new ArrayList<>());
                    childList.add(permissionVO);
                }
            });
        });

        /*再筛选出所有子目录的下一级子目录*/
        if (childList.size() > 0) {
            filterPermissionVO(childList, list);
        }

        /*将子目录对应上一级目录*/
        parentList.forEach(parent -> {
            childList.forEach(child -> {
                if (parent.getId().equals(child.getParentId())) {
                    parent.getChildren().add(child);
                }
            });
        });
    }

    /**
     * 目录排序
     *
     * @param dropId
     * @param dragId
     * @return
     */
    @Transactional
    @Override
    public ResponseResult sortPermission(Long dropId, Long dragId) {
        Subject subject = SecurityUtils.getSubject();
        SysUserDO currentUser = (SysUserDO) subject.getPrincipal();

        SysPermissionDO dropPO = getById(dropId);
        SysPermissionDO dragPO = getById(dragId);
        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.eq("parent_id", dropPO.getParentId());
        queryWrapper.orderByAsc("priority");
        // 获得同级目录下所有元素
        List<SysPermissionDO> list = permissionMapper.selectList(queryWrapper);

        //先删除，再插入、排序
        list.remove(dragPO);
        int dropPriority = dropPO.getPriority();
        dragPO.setPriority(dropPriority);
        dragPO.setUpdateBy(currentUser.getId());
        dragPO.setUpdateTime(new Date());

        permissionMapper.updateById(dragPO);
        list.add(dropPriority - 1, dragPO);

        // priority 字段排序，从1开始
        for (int i = 1; i <= list.size(); i++) {
            SysPermissionDO permissionPO = list.get(i - 1);
            if (i != dropPriority) {
                permissionPO.setPriority(i);
                permissionPO.setUpdateBy(currentUser.getId());
                permissionPO.setUpdateTime(new Date());
                permissionMapper.updateById(permissionPO);
            }
        }

        return ResponseResult.success();
    }

    /**
     * 保存权限
     *
     * @param permissionDO
     * @return
     */
    @Transactional
    @Override
    public ResponseResult savePermission(SysPermissionDO permissionDO) {
        Subject subject = SecurityUtils.getSubject();
        SysUserDO currentUser = (SysUserDO) subject.getPrincipal();
        permissionDO.setUpdateBy(currentUser.getId());
        permissionDO.setUpdateTime(new Date());

        if (permissionDO.getId() == null) {
            permissionDO.setCreateBy(currentUser.getId());
            permissionDO.setCreateTime(new Date());
//            save(permissionDO);
        }
        if (!saveOrUpdate(permissionDO)) {
            throw new BusinessException(ErrorCodeEnum.SAVE_ERROR);
        }
        return ResponseResult.success();
    }

    /**
     * 删除权限
     *
     * @param permissionDO
     * @return
     */
    @Transactional
    @Override
    public ResponseResult deletePermisson(SysPermissionDO permissionDO) {
        // 删除权限表 & 角色权限关联表
        Subject subject = SecurityUtils.getSubject();
        SysUserDO currentUser = (SysUserDO) subject.getPrincipal();

        // 逻辑删除,更新操作人信息
        lambdaUpdate().eq(SysPermissionDO::getId, permissionDO.getId())
                .set(SysPermissionDO::getDeleted, 1).set(SysPermissionDO::getUpdateBy, currentUser.getId()).set(SysPermissionDO::getUpdateTime, new Date())
                .update();

        // 删除权限角色关联关系
        rolePermissionService.deleteRolePermissionByPermissionId(permissionDO.getId());

        return ResponseResult.success();
    }


    /**
     * DO 转 DTO
     *
     * @param list
     * @return
     */
    List<SysPermissionDTO> transferDTO(List<SysPermissionDO> list) {
        List<SysPermissionDTO> resList = new ArrayList<>();
        list.stream().forEach(item -> {
            SysPermissionDTO permissionDTO = new SysPermissionDTO();
            BeanUtils.copyProperties(item, permissionDTO);
            resList.add(permissionDTO);
        });

        return resList;
    }
}
